package camera

import (
	"github.com/go-gl/glfw/v3.2/glfw"
	mgl "github.com/go-gl/mathgl/mgl32"
	"math"
	cfg "gogl/config"
)

const(
	YAW ,PITCH,SPEED,SENSITIVTY float32 = -90,0,2.5,0.01
	ZOOM float64 = 45
)
func NewCamera(position,up mgl.Vec3,yaw,pitch float32) *Camera{
	c := &Camera{
		Position:position,
		WorldUp:up,
		Yaw:yaw,
		Pitch:pitch,
		Front:mgl.Vec3{0,0,-1},
		MovementSpeed:SPEED,
		MouseSensitivity:SENSITIVTY,
		Zoom:ZOOM,
	}
	c.firstPitchDeg = math.Asin(float64(c.Front.Y()))
	c.firstYawDeg = math.Acos(float64(c.Front.X())/math.Cos(c.firstPitchDeg))
	c.updateCameraVectors()
	return c
}
type Camera struct{
	Position,Front,Up,Right,WorldUp mgl.Vec3
	Yaw,Pitch float32
	MovementSpeed,MouseSensitivity float32
	Zoom float64
	firstPitchDeg,firstYawDeg float64
}

func (c Camera) GetViewMatrix() mgl.Mat4{
	return mgl.LookAtV(c.Position,c.Position.Add(c.Front),c.Up)
}
/**
投影矩阵
 */
func (c Camera) GetProjection() mgl.Mat4{
	return mgl.Perspective(mgl.DegToRad(float32(c.Zoom)),float32(cfg.Windows_width)/cfg.Windows_height,0.1,100)
}

func (c *Camera) ProcessKeyboard(key glfw.Key,action glfw.Action){
	var cameraSpeed float32 = 0.05
	if key == glfw.KeyW && action == glfw.Repeat{
		c.Position = c.Position.Add(c.Front.Mul(cameraSpeed))
	}
	if key == glfw.KeyS && action == glfw.Repeat{
		c.Position = c.Position.Sub(c.Front.Mul(cameraSpeed))
	}
	if key == glfw.KeyA && action == glfw.Repeat{
		c.Position = c.Position.Sub(c.Right)
	}
	if key == glfw.KeyD && action == glfw.Repeat{
		c.Position = c.Position.Add(c.Right)
	}
}

func (c *Camera) ProcessMouseMovement(xoffset,yoffset float32){
	xoffset *= c.MouseSensitivity;
	yoffset *= c.MouseSensitivity;

	c.Yaw   += xoffset;
	c.Pitch += yoffset;
	if c.Pitch > 89.0{
		c.Pitch = 89.0
	}
	if c.Pitch < -89.0{
		c.Pitch = -89.0
	}
	c.updateCameraVectors()
}

func (c *Camera) ProcessMouseScroll(yoffset float64){
	if c.Zoom >= 1.0 && c.Zoom <= 45{
		c.Zoom -= yoffset
	}
	if c.Zoom <= 1{
		c.Zoom = 1
	}
	if c.Zoom >= 45{
		c.Zoom = 45
	}
}

func (c *Camera) updateCameraVectors(){
	pitchDeg := float64(mgl.DegToRad(float32(c.Pitch)))
	yawDeg := float64(mgl.DegToRad(float32(c.Yaw)))
	front := mgl.Vec3{
		float32(math.Cos(pitchDeg)*math.Cos(yawDeg)),
		float32(math.Sin(pitchDeg)),
		float32(math.Cos(pitchDeg)*math.Sin(yawDeg)),
	}
	c.Front = front.Normalize()
	c.Right = c.Front.Cross(c.WorldUp).Normalize()
	c.Up = c.Right.Cross(c.Front)
}